package cn.lxh.ymcc.service.impl;

import cn.lxh.ymcc.doc.CourseDoc;
import cn.lxh.ymcc.domain.*;
import cn.lxh.ymcc.dto.CourseAddDto;
import cn.lxh.ymcc.dto.CourseDto;
import cn.lxh.ymcc.dto.MessageSmsDto;
import cn.lxh.ymcc.dto.UserSmsDto;
import cn.lxh.ymcc.feign.MediaFileFeignClient;
import cn.lxh.ymcc.feign.SearchFeignClient;
import cn.lxh.ymcc.mapper.CourseMapper;
import cn.lxh.ymcc.result.JSONResult;
import cn.lxh.ymcc.service.*;
import cn.lxh.ymcc.util.AssertUtil;
import cn.lxh.ymcc.util.StrUtils;
import cn.lxh.ymcc.vo.CourseDetailInfoVo;
import cn.lxh.ymcc.vo.CourserOrderVo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author small.tiger
 * @since 2022-07-20
 */
@Service

public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {
    @Autowired
    private ITeacherService teacherService;
    @Autowired
    private ICourseDetailService courseDetailService;
    @Autowired
    private ICourseResourceService courseResourceService;
    @Autowired
    private ICourseMarketService courseMarketService;
    @Autowired
    private ICourseTeacherService courseTeacherService;
    @Autowired
    private ICourseTypeService courseTypeService;
    @Autowired
    private ICourseSummaryService courseSummaryService;
    @Autowired
    private ICourseChapterService courseChapterService;
    //注入使用feign接口
    @Autowired
    private SearchFeignClient searchFeignClient;
//    是章节视频的微服务
    @Autowired
    private MediaFileFeignClient mediaFileFeignClient;

//    使用rq
    @Autowired
    private RocketMQTemplate rocketMQTemplate;



    /**
     * 校验--jsr303---对象 controller注解。。对象里面的注解
     * 查询这个课程是否被注册了--断言-isnull
     * 初始化数据
     * @param dto
     */
    @Override
    public void saveBigTable(CourseAddDto dto) {
        //jsr303 的校验
        Course course = dto.getCourse();
        CourseDetail courseDetail = dto.getCourseDetail();
        CourseMarket courseMarket = dto.getCourseMarket();
        CourseResource courseResource = dto.getCourseResource();
        List<Long> teacharIds = dto.getTeacharIds();
//        根据课程明智查询============
        Course courseTmp = selectByCouserName(course.getName());
        AssertUtil.isNull(courseTmp, "这个课程已经存在了-好朋友");
//        初始化数据
        course.setStatus(0);
        course.setLoginId(1L);
        course.setLoginUserName("暂时名字");

        List<Teacher> teachers = teacherService.selectBatchIds(teacharIds);
        StringBuffer sb = new StringBuffer();
        for (Teacher teacher : teachers) {
            sb.append(teacher.getName()).append(",");
        }
//   sb中有所有的teacher的名字
        course.setTeacherNames(sb.toString());
        insert(course);
//        a保存细节表 和course表id一致
        courseDetail.setId(course.getId());
        courseDetailService.insert(courseDetail);
//       保存课程销售
        courseMarket.setId(course.getId());
//        默认初始值价格
        courseMarket.setPrice(new BigDecimal(0));

        courseMarketService.insert(courseMarket);
//        保存课程讲师
        for (Long teacharId : teacharIds) {
            CourseTeacher courseTeacher = new CourseTeacher();
            courseTeacher.setCourseId(course.getId());
            courseTeacher.setTeacherId(teacharId);
            courseTeacherService.insert(courseTeacher);
        }
//        保存课程资源
        courseResource.setCourseId(course.getId());
        courseResourceService.insert(courseResource);
//       初始化课程统计
        CourseSummary courseSummary = new CourseSummary();
        courseSummary.setId(course.getId());
        courseSummaryService.insert(courseSummary);
//      课程类型表中的课程数
        CourseType type = courseTypeService.selectById(course.getCourseTypeId());
        type.setTotalCount(type.getTotalCount() + 1);
        courseTypeService.updateById(type);
    }

    /**
     * 课程上线
     * 校验这个课程是否再 断言
     * 查出这条数据
     *
     * 修改状态。修改表
     * 使用feign 保存search 课表中
     *   重点
     *   保存到elsticsearch中
     *
     * @param courseId
     */
    @Override
    public void onLineCourse(Long courseId) {
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course,"这个课程不存在");

        boolean offLine = course.getStatus() == 0;
        AssertUtil.isTrue(offLine,"不要重复上架。");

        course.setStatus(1);
        course.setOnlineTime(new Date());
        updateById(course);
//        Es 相关部分
//                  ----将需要用到的表和字段 找到
//        为service-search编写feign接口
//        在课程微服务中
        CourseType type = courseTypeService.selectById(course.getCourseTypeId());
        CourseMarket courseMarket = courseMarketService.selectById(courseId);
        CourseSummary courseSummary = courseSummaryService.selectById(courseId);
        //设置需要保存到Es的字段
        CourseDoc doc = new CourseDoc();
        /*
        BeenUtils：提供一个方法。直接将对象里面的字段一一对应。。
        不一样的字段 需要单独处理
         */
        BeanUtils.copyProperties(course,doc);
        BeanUtils.copyProperties(courseMarket,doc);
        BeanUtils.copyProperties(courseSummary,doc);

        doc.setCourseTypeName(type.getName());       //这里要单独赋值
        String chargeName = courseMarket.getCharge() == 1 ? "免费" : "收费";
        doc.setChargeName(chargeName);

        JSONResult jsonResult = searchFeignClient.saveCourse(doc);
//        -----------------------这里需要转一下
        AssertUtil.isTrue(jsonResult.isSuccess(),"课程发布失败");

        //课程发布成功了，推消息===========================
        sendMessage(doc);

    }

    /**
     * 发消息
     * @param doc
     */
    private void sendMessage(CourseDoc doc) {
        /**
         * 生产者的消息体，到底该放什么
         *
         * 发送的消息内容是什么 content
         * 消息title
         * List<Long> userIds;
         *
         * MessageSmsDto {
         *     String content;
         *     String title;
         *     List<UserSmsDto> users;
         * }
         *
         * UserSmsDto{
         *         Long id;
         *         String phone;
         * }
         */
        MessageSmsDto messageSmsDto = new MessageSmsDto();
        messageSmsDto.setTitle("新课程发布"+doc.getName());
        messageSmsDto.setContent("亲，您关注的"+
                doc.getCourseTypeName()+
                "相关的课程"+doc.getName()+
                "已上线，尝鲜地址：<a href='localhost:6002/list.html?coursId="+doc.getId()+"'");
        List<UserSmsDto> userSmsDtos = Arrays.asList(
                new UserSmsDto(1L, "13470062222"),
                new UserSmsDto(2L, "13470061111")
        );
        messageSmsDto.setUsers(userSmsDtos);
        /*
        重点 集成rq ---导包 -yml 注入
         */
        rocketMQTemplate.sendOneWay(
                "course-topic:course-tag",
                JSON.toJSONString(messageSmsDto)
        );
        //在common中 消费消息
    }

    /**
     * 下架
     * @param courseId
     */
    @Override
    public void offLineCourse(Long courseId) {
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course,"这个课程不存在");

        boolean offLine = course.getStatus() == 1;
        AssertUtil.isTrue(offLine,"不要重复下架。");

        course.setStatus(0);
        course.setOnlineTime(new Date());
        updateById(course);

//        微服务的删除

        //        在课程微服务中
        CourseType type = courseTypeService.selectById(course.getCourseTypeId());
        CourseMarket courseMarket = courseMarketService.selectById(courseId);
        CourseSummary courseSummary = courseSummaryService.selectById(courseId);

        CourseDoc doc = new CourseDoc();
        BeanUtils.copyProperties(course,doc);
        BeanUtils.copyProperties(courseMarket,doc);
        BeanUtils.copyProperties(courseSummary,doc);

        doc.setCourseTypeName(type.getName());       //这里要单独赋值
        String chargeName = courseMarket.getCharge() == 1 ? "免费" : "收费";
        doc.setChargeName(chargeName);

        JSONResult jsonResult = searchFeignClient.deleteCourse(doc);
//        -----------------------这里需要转一下
        AssertUtil.isTrue(jsonResult.isSuccess(),"课程删除失败");

    }

    /**
     * 详情页面的展示
     *  1、检验一堆 ---- courserID 必须有 。。。这个course课程必须有----上线状态必须有=1
     *  2、
     *  3、课程的老师们
     *                流式编程，和landa表达式
     *  4、封装所有的章节
     *             --主键强一致===courseid 就是下面 垂直分表的id
     *  5、feigh的使用---media的微服务里面视频信息
     *      -- 要为每一个章节查询对应的视屏
     *          media微服务编写controller查询章节视屏
     *         为media服务编写Feign接口+降级方案
     *         course微服务依赖media的Feign接口，调用media查询章节视屏
     * @param courseId
     * @return
     */
    @Override
    public CourseDetailInfoVo searchCourseDetail(Long courseId) {

        AssertUtil.isNotNull(courseId,"空的课程ID");
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course,"这个课程已经下架了");
        boolean onLine = course.getStatus() == 1;
        AssertUtil.isTrue(onLine,"清联系客服，上架");

        CourseDetail courseDetail = courseDetailService.selectById(courseId);
        CourseMarket courseMarket = courseMarketService.selectById(courseId);
        CourseSummary courseSummary = courseSummaryService.selectById(courseId);
        /*
         课程的老师们
               流式编程，和landa表达式
         */
        Wrapper<CourseTeacher> ctwrapper = new EntityWrapper<>();
        ctwrapper.eq("course_id",courseId);
        List<CourseTeacher> courseTeachers = courseTeacherService.selectList(ctwrapper);
        List<Long> teacherIds = courseTeachers.stream().map(teacher -> teacher.getTeacherId()).collect(Collectors.toList());
        List<Teacher> teachers = teacherService.selectBatchIds(teacherIds);
        /*
        封装所有的章节
            --主键强一致===courseid 就是下面 垂直分表的id
         */
        Wrapper<CourseChapter> ccwrapper = new EntityWrapper<>();
        ccwrapper.eq("course_id",courseId);
        List<CourseChapter> chapters = courseChapterService.selectList(ccwrapper);
        /**
         * 电泳media的feign的 微服务
         *      --将视频内容封装到章节中
         *      将chapter的list<chapterId> 闯过去
         */
        chapters.forEach(chapter->{
            JSONResult jsonResult = mediaFileFeignClient.searchMediaFiles(chapter.getId());
            if(jsonResult.isSuccess() && jsonResult.getData() != null){
                List<MediaFile> fileList = JSONObject.parseArray(jsonResult.getData().toString(), MediaFile.class);
                chapter.getMediaFiles().addAll(fileList);
            }
        });
        CourseDetailInfoVo vo = new CourseDetailInfoVo();
        vo.setCourse(course);
        vo.setCourseChapters(chapters);
        vo.setCourseMarket(courseMarket);
        vo.setCourseSummary(courseSummary);
        vo.setCourseDetail(courseDetail);
        vo.setTeachers(teachers);
        return vo;
    }

    /**
     * 订单上面的展示
     *        course名称   coursemarket金额。。。等等 两张表
     *        bigdicemal的金额
     * 业务方面
     *      -校验
     *      -空校验
     *      -string类型的ids。。换成long类型的
     *      -重复课程的处理-zet
     *   -健壮性判断：list中id和set中的ld是否转换成功
     *      -.根据每个课程Id查询课程 + 销售表
     *      -封装课程和销售成 CourseDto
     *      -状态校验
     * @param courseIds
     * @return
     */
    @Override
    public CourserOrderVo searchCourseOrder(String courseIds) {
        //转换成long类型--strUtils里面的方法
        List<Long> ids = StrUtils.splitStr2LongArr(courseIds, ",");
        Set<Long> setIds = ids.stream().collect(Collectors.toSet());
        AssertUtil.isNotNull(setIds,"没有选中课程");
        //id个数是否相等。没有传递重复ID
        boolean ok = ids.size() == setIds.size();
        AssertUtil.isTrue(ok,"非法：list和set转换有问题");
        List<CourseDto> courseInfos = new ArrayList<>();
        BigDecimal totalAmount = new BigDecimal(0);
        //根据每个课程Id查询课程 + 销售表
        for (Long id : setIds) {
            Course course = selectById(id);
            AssertUtil.isNotNull(course,"亲，这个课程不存在");
            boolean state = course.getStatus() == 1;
            AssertUtil.isTrue(state,"这个课程还未上架，敬请期待");
            CourseMarket courseMarket = courseMarketService.selectById(id);
            AssertUtil.isNotNull(courseMarket,"请求非法！");
            //将这个对象封装到courseDto中
            CourseDto courseDto = new CourseDto(course, courseMarket);
            courseInfos.add(courseDto);
            totalAmount = totalAmount.add(courseMarket.getPrice());
        }
        CourserOrderVo vo = new CourserOrderVo(courseInfos, totalAmount);

        return vo;
    }


    /**
     * 根据名字查询的方法
     * @param name
     * @return
     */
    private Course selectByCouserName(String name) {
        Wrapper tWrapper = new EntityWrapper();
        tWrapper.eq("name",name);
       return selectOne(tWrapper);
    }
}
